import { nextTick } from '@/ts/base/common/timer';
import { AssignStatusType, NodeType } from '@/ts/base/enum';
import { InstanceDataModel } from '@/ts/base/model';
import { XAssignTask } from '@/ts/base/schema';
import { IForm, IReport, IWork } from '@/ts/core';
import { formatDate } from '@/utils';
import { Button, message, Modal, Progress, Switch, Typography } from 'antd';
import React, { useState } from 'react';
import { AssignTask, IAssignTask } from '@/ts/core/work/assign';
import { IAssignTaskTree } from '@/ts/core/work/assignTree';
import { deepClone } from '@/ts/base/common';

interface Props {
  assignTask: IAssignTask;
  visible: boolean;
  onClose: () => void;
}

function isNeedFill(task: XAssignTask) {
  return !(
    task.thingId &&
    (task.isAutoFill || task.taskStatus == AssignStatusType.FINISHED)
  );
}

export function AssignFillData(props: Props) {
  const [skipSubmitted, setSkipSubmitted] = useState(false);
  const [progress, setProgress] = useState(0);
  const [msg, setMsg] = useState('');
  const [errors, setErrors] = useState<string[]>([]);
  const [isStart, setIsStart] = useState(false);

  async function startSync() {
    try {
      setMsg('加载完整树形及任务接收');
      const taskTree = await props.assignTask.loadTree();
      if (!taskTree) {
        setErrors(['加载树形失败']);
        return;
      }
      const tasks = await taskTree.loadSubNodes(props.assignTask.id, true);
      if (!tasks.length) {
        setErrors(['加载任务节点失败']);
        return;
      }

      setMsg('查找办事信息');
      const total = tasks.length;
      let err: string[] = [];
      let current = 0;

      const work = await props.assignTask.loadWork(true, true);
      if (!work) {
        setErrors(['未找到办事']);
        return;
      }
      let workNode = (await work.loadNode())!;
      if (!workNode) {
        setErrors(['未找到提交节点']);
        return;
      }
      const forms = [...work.primaryForms, ...work.detailForms];
      const formMap = forms.reduce<Dictionary<IForm | IReport>>((a, v) => {
        a[v.id] = v;
        return a;
      }, {});
      await nextTick();
      for (const task of tasks) {
        if (!task.period) {
          task.period = props.assignTask.period;
          task.assignContent = deepClone(props.assignTask.distContent);
          task.periodType = props.assignTask.metadata.periodType;
          task.assignType = props.assignTask.metadata.assignType;
          task.assignName = props.assignTask.metadata.assignName;
        }
        await taskNodeFill(task, taskTree, err, formMap, work);
        current++;
        setProgress(parseFloat(((current / total) * 100).toFixed(2)));
        await nextTick();
      }
      if (err.length > 0) {
        setErrors(err);
      } else {
        setMsg('补全成功');
      }
    } catch (error) {
      setErrors([error instanceof Error ? error.message : String(error)]);
    }
  }

  async function taskNodeFill(
    node: XAssignTask,
    taskTree: IAssignTaskTree,
    err: string[],
    formMap: Dictionary<IForm | IReport>,
    work: IWork,
  ): Promise<[string, boolean] | undefined> {
    if (!isNeedFill(node)) {
      return [node.id, true];
    }
    if (node.nodeType == NodeType.Summary) {
      return [node.id, true];
    }
    const nodeInfo = `${node.name} ${node.nodeTypeName}：`;
    const assignTask = new AssignTask(node, taskTree.directory.target);
    if (node.instanceId && !skipSubmitted) {
      setMsg(`正在保存 ${node.name} ${node.nodeTypeName}`);
      const detail = await assignTask.loadInstanceDetail(node.instanceId);
      if (!detail) {
        err.push(nodeInfo + `加载流程实例失败`);
        return [node.id, false];
      }
      const data: InstanceDataModel = JSON.parse(detail.data || '{}');
      const thingId: Dictionary<string[]> = {};
      for (const [formId, value] of Object.entries(data.data)) {
        const rows = value.at(-1)!.after;
        thingId[formId] = rows.map((d) => d.id);

        const form = formMap[formId];
        if (!form) {
          err.push(nodeInfo + `找不到 ${formId} 对应表单`);
          continue;
        }

        rows.forEach((row) => {
          for (const attr of form.fields) {
            if (attr.valueType == '对象型') {
              row[`R${attr.propId}`] = row[attr.id];
            } else {
              row[`T${attr.propId}`] = row[attr.id];
            }
            delete row[attr.id];
          }
          row.remark = `自动保存`;
          row.archives ||= {};
          row.assignId = node.id;
        });
        const ret = await form.thingColl.replaceMany(rows);
        if (ret.length != rows.length) {
          err.push(nodeInfo + `保存表单 ${form.name} 数据失败`);
        }
      }
      node.thingId = thingId;
      node.isAutoFill = true;
      node.taskStatus = AssignStatusType.FINISHED;
      const res = await assignTask.target.resource.assignTaskPublicColl!.replace(node);
      if (!res) {
        err.push(nodeInfo + `更新任务接收状态失败`);
        return [node.id, false];
      }
    } else {
      node.thingId ||= {};
      setMsg(`正在通过上期数据补全 ${node.name} ${node.nodeTypeName}`);
      const lastPeriod = assignTask.getHistoryPeriod(-1);
      const [lastTask] = await assignTask.target.resource.assignTaskPublicColl!.loadSpace(
        {
          options: {
            match: {
              period: lastPeriod,
              assignName: node.assignName,
              belongId: node.belongId,
              nodeType: node.nodeType,
            },
          },
        },
      );
      if (!lastTask) {
        err.push(nodeInfo + `上期任务未接收或是新增单位`);
        return [node.id, false];
      }

      if (!lastTask.thingId) {
        err.push(nodeInfo + `上期报表未完结`);
        return [node.id, false];
      }

      const thingId: Dictionary<string[]> = {};
      for (const form of work!.forms) {
        const ids = lastTask.thingId[form.id];
        const data = await form.thingColl.loadSpace({
          options: {
            match: {
              id: {
                _in_: ids,
              },
            },
          },
        });

        // 将新的任务接收的字段标记进去
        data.forEach((d) => {
          d.id = 'snowId()';
          d.createUser = node.receiveUserId;
          d.createTime = formatDate(new Date(), 'yyyy-MM-dd HH:mm:ss.S');
          d.remark = '自动取上月数';
          d.periodType = node.periodType;
          d.assignId = node.id;
          d.nodeType = node.nodeType;
          d.belongId = node.belongId;
          d.targetId = node.targetId;
        });
        const newData = await form.thingColl.replaceMany(data);

        thingId[form.id] = newData.map((d: { id: any }) => d.id);
        if (newData.length != data.length) {
          err.push(nodeInfo + `保存 ${form.name} 表单数据失败`);
        }
      }
      node.thingId = thingId;
      node.isAutoFill = true;
      node.taskStatus = AssignStatusType.FINISHED;
      const res = await assignTask.target.resource.assignTaskPublicColl!.replace(node);
      if (!res) {
        err.push(nodeInfo + `更新任务接收状态失败`);
        return [node.id, false];
      }
    }
  }

  return (
    <Modal
      open={props.visible}
      title="批量数据补全"
      width={640}
      onOk={props.onClose}
      onCancel={props.onClose}>
      <div className="flex flex-col" style={{ height: '50vh', overflow: 'auto' }}>
        <div style={{ padding: '8px', marginBottom: '8px' }}>
          <div>将下级未填报的单位自动补全并保存，不进行汇总</div>
          <div>补全前请刷新页面确保数据最新，且不要进行树形筛选</div>
          <div>耗时极长，请在系统空闲时进行，一旦开始操作不可撤销！</div>
          <div>完成后根据错误提示检查未成功的节点，如遇网络问题可以重试</div>
          <div style={{ marginTop: '16px' }}>
            <Switch checked={skipSubmitted} onChange={setSkipSubmitted} />
            <span> 跳过审核中单位，直接取上期数</span>
          </div>
        </div>
        {isStart ? (
          <div className="flex flex-col flex-auto justify-center items-center">
            <div
              style={{
                whiteSpace: 'pre-wrap',
                marginBottom: '16px',
              }}>
              {errors.length > 0 ? (
                <Typography style={{ color: 'red' }}>
                  <div>遇到 {errors.length} 个错误</div>
                  <ul>
                    {errors.map((e, i) => (
                      <li key={i} style={{ listStyle: 'initial' }}>
                        {e}
                      </li>
                    ))}
                  </ul>
                </Typography>
              ) : (
                <div>{msg}</div>
              )}
            </div>
            <Progress percent={progress} style={{ width: '75%' }} />
          </div>
        ) : (
          <Button
            type="primary"
            onClick={() => {
              setIsStart(true);
              setErrors([]);
              setMsg('');
              if (
                !props.assignTask.taskStatus ||
                props.assignTask.taskStatus == 'empty'
              ) {
                message.warning('当前节点未接收');
                return;
              }
              startSync();
            }}>
            开始补全
          </Button>
        )}
      </div>
    </Modal>
  );
}
